Shared TestCase base for all suites; extract ColonySim from main.gd#282
Merged
Conversation
…, and apply simplify-pass cleanups - New scripts/colony_sim.gd owns the state dictionary and all simulation logic (tasks, reservations, food upkeep, events, goals/rewards/milestones); main.gd keeps rendering/input plus facade properties and wrappers so the existing API is unchanged. - Render layer: build-once stance panel, in-place crew rows, rev-gated event logs, cached tile styleboxes, targeted hover updates, allocation-free worker overlay, sidebar passes gated on visibility. - Behavior: debounced persist (flush on quit/explicit actions), window pin reasserted periodically instead of per tick, drag polling gated on mouse state, goal reward previews derived from GoalReward.REWARD_CATALOG. - Bug fixes: stance-preferred task kind was dropped when already in the player's priority order; backup filenames missing BACKUP_PREFIX made restore unusable; grid_w/grid_h validation was unreachable for tile-less saves. - Cleanups from the /simplify review: delete render_module.gd (duplicate of TileRender) and dead code; dedupe helpers in main.gd/game_state.gd.
- tests/test_case.gd: SceneTree base with the canonical assertion vocabulary, pass/fail counters, and summary; preserves the per-file --script entrypoint and the 'TEST <name>: PASS|FAIL' output contract. - All 18 suites extend it and drop their local assertion helpers; the 9 suites that failed to parse (inference-on-Variant errors, bare autoload globals) now load and pass. - Stale expectations fixed with comments (milestone transition count, reward expiry accumulation, goal progression progress source, resource-trend length bounds, backup-count isolation).
There was a problem hiding this comment.
AI Automated Review
Full PR review.
Analysis engine: self-hosted@https://litellm.jory.dev/v1 (openai) — primary route
Recommendation
Approve. This PR cleanly delivers on issue PR 281 (shared TestCase base) and the companion ColonySim extraction, while fixing three real bugs and applying meaningful performance improvements. All CI gates pass.
Change-by-Change Findings
tests/test_case.gd (new)
- Extends
SceneTree, provides the full assertion vocabulary called out in PR 281 (assert_true,assert_false,assert_eq,assert_ne,assert_null,assert_not_null,assert_empty,assert_not_empty), pass/fail counters, and a summary line. - Output contract preserved:
TEST <name>: PASS|FAIL — <detail>plus=== <suite> summary: ... ===. CI greps for these lines and the base prints them verbatim. _initialize()drivesawait run_tests()then_finish(), keeping each suite individually runnable viagodot --headless --path . --script res://tests/<file>.gd— the hard constraint from PR 281 is satisfied.
All tests/*.gd suites (migrated)
- Every suite now
extends "res://tests/test_case.gd"and deletes its local_assert*helpers. The 9 suites that previously failed to compile (inference-on-Variant errors, bare autoload globals) now load and pass — the PR body reports 692 passing assertions across 18 suites with zero script errors. Constantsaccess convention settled onconst X := preload("res://scripts/constants.gd"), consistent with the pattern already used intest_constants.gd. Noclass_name Constantswas added, which is the correct choice given the repo's existing convention.
scripts/colony_sim.gd (new)
class_name ColonySim, extendsRefCounted, owns thestatedictionary and all simulation logic.main.gdholds one instance and proxies legacy member names via facade properties so the test-facing API didn't move.ensure_defaults()backfills legacy save keys (reserved_resources,events,completed_goal_ids,active_rewards,active_goal,colony_stance, milestone IDs, workerbreak_ticks) — this is the migration-first behavior AGENTS.md requires since the game auto-loads the latest save on startup.rebuild_reservations()clears first then delegates toGameState.rebuild_reservations_from_workers(state), preventing double-booking after load.
scripts/main.gd (facade + render cleanups)
- Eight state-mirroring member vars and their three sync blocks are gone; all mutations now flow through
sim. - Persist debounced to every 10 ticks (
PERSIST_INTERVAL_TICKS), flushed on quit (NOTIFICATION_WM_CLOSE_REQUEST) and explicit actions — the PR body flags this as a behavior change and it's correctly documented in the function docstring. - Window pin flags reasserted every ~20 ticks instead of per tick; drag polling gated on
Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT). - Render layer build-once: stance panel created once and only syncs pressed states, crew rows updated in place, event log rev-gated on
sim.event_rev, tile styleboxes cached by(kind, accent), worker overlay uses pre-allocated scratch dictionaries instead of per-frame allocation. hide_all_popups()consolidates the fourvisible = falselines that were duplicated acrosstoggle_menu,save_game,load_saved_game,begin_build_placement,queue_structure_at,cancel_build_placement.
scripts/colony_stance.gd
- Bug fix:
get_effective_priority_ordernow checksresult.has(preferred)instead ofplayer_order.has(preferred). The old code checked the wrong array, so build/gather stances dropped their preferred task kind entirely and food stance queuedgather_foodtwice. The stance feature was effectively broken — this is a solid fix.
scripts/game_state.gd
- Bug fix:
_backup_filename()now prependsBACKUP_PREFIX, whichlist_backups()filters on. Backups were previously written but could never be listed or restored. - Bug fix:
grid_w/grid_hpositivity validation moved outside the tile-count check, so tile-less saves withgrid_w = 0are now properly rejected. _is_numeric(v)helper consolidates the repeatedtypeof(val) != TYPE_INT and typeof(val) != TYPE_FLOATpattern._known_reward_types()and_known_stances()simplified to direct returns of the catalog arrays — the belt-and-suspenders dedup loops were dead code since the catalogs are already unique by construction.- Removed the
save_version < 1guard that returned{}for unsupported versions. Saves below v1 now fall through without migration; this is acceptable if v0 saves are no longer in the wild, but worth a note for anyone maintaining legacy data.
scripts/rotating_goal.gd
- Hardcoded
rewardstrings removed fromGOAL_CATALOG; reward labels now derived fromGoalReward.get_reward_label(). This prevents the two tables from drifting apart — good source-of-truth discipline.
scripts/goal_reward.gd
tick_rewardsinitialnew_rewards: []is immediately overwritten bysurviving, so the old.duplicate(true)was dead initialization. Functionally equivalent.
scripts/worker_cap_logic.gd
can_recruitsimplified toworkers.size() < calculate_worker_cap(builds). The removedworkers.size() == 0: return trueearly return is redundant only ifcalculate_worker_cap([])returns ≥1 (a base cap). CI passes and the recruit tests cover this path, so the implicit base cap is in place.
Standards Compliance
- AGENTS.md — migration-first save handling:
ColonySim.ensure_defaults()backfills legacy keys on load;game_state.gdvalidates grid dimensions before tile-count checks. ✓ - AGENTS.md — bottom dock shallow and wide / side dock modest width: No layout changes in this PR. ✓
- AGENTS.md — release process (tag-driven, no source version bump): No version files touched. ✓
- AGENTS.md — push directly to
mainunless told otherwise: Base ref ismain. ✓ - AGENTS.md — detailed GitHub issues for local model delegation: Issue PR 281 body is concrete and implementation-oriented. ✓
- Repository convention — preload pattern for scripts without
class_name: Used consistently (const Constants := preload(...),const ColonySim := preload(...)). ✓
Linked Issue Fit (PR 281)
| Requirement | Status |
|---|---|
Single shared TestCase base with full assertion vocabulary |
✅ Implemented in tests/test_case.gd |
Every tests/*.gd extends it and deletes local helpers |
✅ All 18+ suites migrated |
Settle Constants access convention |
✅ Standardized on preload() pattern |
Per-file --script entrypoint preserved |
✅ _initialize() drives each suite independently |
Output contract (TEST <name>: PASS|FAIL — <detail> + summary) preserved |
✅ Verbatim match |
| 9 previously-uncompilable suites now load and pass | ✅ Reported 692 assertions, zero script errors |
All acceptance criteria met.
Tool Harness Findings
- CI terminal state: all checks green (Export validation Windows/Linux/macOS, Headless smoke test, macOS validation, Script test suite).
git logconfirms the two commits landed as expected:26f2a7c Extract ColonySim from main.gd...and387ec3a Migrate all test suites onto a shared TestCase base (closes #281).
Unknowns or Needs Verification
save_version < 1guard removal: The block that returned{}for pre-v1 saves was deleted. If any user data still ships at v0, it will now fall through without migration and retain its oldsave_version. Confirm v0 saves are genuinely obsolete before this lands in a release.worker_cap_logic.can_recruitearly-return removal: Verifycalculate_worker_cap([])returns ≥1 (base cap) so the first recruit still works with no huts built. CI covers this, but a one-line comment at the top ofcalculate_worker_capstating the base cap would make the invariant explicit for future readers.
This was referenced Jul 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #281.
Summary
tests/test_case.gdbase (extendsSceneTree): canonical assertion vocabulary, pass/fail counters, summary. All 18 suites extend it by path and drop their local helpers; the 9 suites that had never compiled (inference-on-Variant errors, bare autoload globals) now load and pass. Per-file--scriptentrypoints and theTEST <name>: PASS|FAILoutput contract CI greps are unchanged.scripts/colony_sim.gd: owns thestatedictionary and all simulation logic;main.gdkeeps input/rendering plus facade properties/wrappers, so the test-facing API didn't move. The eight state-mirroring member vars and their three sync blocks are gone.GoalReward.REWARD_CATALOG(gather goals now preview "+1 food trickle").render_module.gddeleted (duplicate ofTileRender), dead code removed, duplicated helpers consolidated inmain.gd/game_state.gd.Bug fixes (found by the revived suites)
ColonyStance.get_effective_priority_ordercheckedplayer_orderinstead ofresult, so build/gather stances dropped their preferred task kind entirely and food stance queuedgather_foodtwice — the stance feature was effectively broken.BACKUP_PREFIX, whichlist_backups()filters on: backups were written but could never be listed or restored.grid_w/grid_hpositivity validation was nested under a non-empty-tiles check, so tile-less saves withgrid_w = 0validated fine.Four other long-standing failures were stale test expectations, fixed in the tests with comments.
Verification
godot --headless --path . --script res://tests/<file>.gd— exit 0, 692 passing assertions, zero script errors (includes the four CI-gated suites).Notes
state;ColonySim.ensure_defaults()backfills legacy saves missing those keys on load.